/**
 * Array methods.
 */
Array.prototype.collect = function(f) {
	var newArray = [];
	this.each(function(array, index) {
		newArray[index] = f.apply(array[index], [array, index]);
	});
	return newArray;
};
Array.prototype.each = function(f) {
	for (var i = 0; i < this.length; i++) {
		f.apply(this[i], [this, i]);
	}
};
Array.prototype.empty = function() {
	return 0 === this.length;
};
Array.prototype.first = function(n) {
	if (n) {
		if (n > this.length) {
			return this;
		} else {
			var r = [];
			for (var i = 0; i < n; i++) {
				r.push(this[i]);
			}
			return r;
		}
	} else {
		return this[0];
	}
};
Array.prototype.last = function(n) {
	if (n) {
		if (n > this.length) {
			return this;
		} else {
			var r = [];
			for (var i = this.length - n; i < this.length; i++) {
				r.push(this[i]);
			}
			return r;
		}
	} else {
		return this[this.length - 1];
	}
};
Array.prototype.reverse = function() {
	var r = [];
	for (var i = this.length - 1; i >= 0; i--) {
		r.push(this[i]);
	}
	return r;
};
Array.prototype.unique = function() {
    var o = {}, i, l = this.length, r = [];    
    for (i = 0; i < l; i++) {
    	// Preserve data type
    	o[this[i]] = this[i];
    }    
    for (i in o) {
    	r.push(o[i]);
    }    
    return r;
};

/**
 * Number methods
 */
Number.prototype.times = function(f) {
	for (var i = 0; i < this; i++) {
		f.apply(i, [this]);
	}
};
Number.prototype.upto = function(end, f) {
	this.step(end, 1, f);
};
Number.prototype.downto = function(end, f) {
	this.step(end, 1, f);
};
Number.prototype.step = function(end, step, f) {
	if (this <= end) {
		for (var i = this; i <= end; i += step) {
			f.apply(i, [this, end, step]);
		}
	} else {
		for (var i = this; i >= end; i -= step) {
			f.apply(i, [this, end, step]);
		}
	}
};

/**
 * String methods
 */
String.prototype.chop = function() {
	return this.substr(0, this.length - 1);
};
String.prototype.reverse = function() {
	var r = "";
	for (var i = this.length - 1; i >= 0; i--) {
		r += this.charAt(i);
	}
	return r;
};
String.prototype.times = function(n) {
	var r = "";
	for (var i = 1; i <= n; i++) {
		r += this;
	}
	return r;
};
String.prototype.ltrim = function() {
	return this.replace(/^\s+/,'');
};
String.prototype.rtrim = function() {
	return this.replace(/\s+$/,'');
};
String.prototype.trim = function() {
	this.ltrim().rtrim();
};